package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/pkg/errors"
	"net/http"
)

type Person struct {
	id   string
	name string
}

func dao() (*Person, error) {
	db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/homework")

	if err != nil {
		return nil, errors.Wrap(err, "dao:open database failed")
	}
	defer func() {
		err = db.Close()
		if err != nil {
			fmt.Println("err:", err)
		}
	}()

	p := new(Person)
	querySql := "select id, name from person where id = 1"
	row := db.QueryRow(querySql)
	err = row.Scan(p.id, p.name)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			//对于sql.ErrNoRows,dao作为底层，和其他库交互，应该将err包装后返给上层
			//原因：
			// 1、上层的错误处理不应依赖 dao 层交互的库，如 mysql/es/mongo
			// 2、未查到数据记录，在 service 层对不同业务场景有不同的业务逻辑
			return nil, errors.Wrap(err, "not found data record")
		}
	}
	return p, nil
}

func service() (*Person, error) {
	return dao()
}

func api() {
	http.HandleFunc("/index", func(w http.ResponseWriter, r *http.Request) {
		_, err := service()
		if err != nil {
			fmt.Printf("root error: %T %v\n", errors.Cause(err), errors.Cause(err))
			fmt.Printf("stack trace:\n%+v\n", err)
			return
		}
	})
	err := http.ListenAndServe("127.0.0.1:8000", nil)
	if err != nil {
		fmt.Println("err:", err)
	}
}
